/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2013.12.10                                          *
 *                                                                       *
 *************************************************************************/

//declaration header
#include "COMMON/tbox/LogMessage.h"

#include <iostream>
#include <fstream> // std::filebuf

//COMMON headers
#include "COMMON/info/InfoManager.h"
#include "COMMON/info/CommonInfo.h"
//#include "COMMON/info/MeshInfo.h"
#include "COMMON/tbox/MathUtilities.h"
#include "COMMON/smlt/SimulationEnsemble.h"



namespace FreeMAPs
{

std::string
LogMessage::get_line_number_message (
    const InputDatabase* db,
    const std::string& key)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    int line_number = 0;
    if (db->key_exists (key))
    {
        line_number = db->get_line_number (key);
    }
    else
    {
        line_number = db->get_line_number();
    }

    std::ostringstream oss;
    oss << "in \"" << db->get_file_name() << "\"\nin line " << line_number << '\n';
    oss << "in \"" << db->get_nested_name () << "\"";
    return oss.str();
}



std::string
LogMessage::get_line_number_message (
    const InputDatabase* db)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    const int line_number = db->get_line_number ();
    std::ostringstream oss;
    oss << "in \"" << db->get_file_name() << "\"\nin line " << line_number << '\n';
    oss << "in \"" << db->get_nested_name () << "\"";
    return oss.str();
}



void
LogMessage::disallow_using_default_value (
    const InputDatabase* db,
    const std::string& key)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    std::ostringstream os;

    os << get_line_number_message (db, key) << '\n';
    os << "not supported of \"" << key << "\" = \"FREEMAPS_DEFAULT_VALUE\".";

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::disallow_missing(
    const InputDatabase* db,
    const std::string& key)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    FREEMAPS_ASSERT (!db->key_exists (key));

    std::ostringstream os;

    os << get_line_number_message (db, key) << '\n';
    os << "keyword \"" << key << "\" MUST be set.";

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::disallow_using_blank_string(
    const InputDatabase* db,
    const std::string& key)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    if (db->key_exists (key))
    {
        std::ostringstream os;
        os << get_line_number_message (db, key) << '\n';
        os << "\"" << key << "\" can't have space string.";

        FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
    }
}



void
LogMessage::disallow_using_array(
    const InputDatabase* db,
    const std::string& key)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    FREEMAPS_ASSERT (db->key_exists (key));
    FREEMAPS_ASSERT_GT (db->get_array_size (key), 1);

    std::ostringstream os;

    os << get_line_number_message (db, key) << '\n';
    os << "the size of \"" << key << "\" is " << db->get_array_size (key) << '\n';
    os << "it should be a scalar type(size = 1) instead of an vector type";

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::disallow_type(
    const InputDatabase* db,
    const std::string& key,
    const std::string& allowable_type)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    FREEMAPS_ASSERT (db->key_exists (key));

    std::ostringstream os;

    os << get_line_number_message (db, key) << '\n';
    os << "not supported type of \"" << key << "\" whose type is \"";
    os << Utilities::enum_to_string (db->get_key_type (key)) << "\"\n";
    os << "the allowable type is: " << " \"" << allowable_type << "\"";

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::disallow_type(
    const InputDatabase* db,
    const std::string& key,
    const std::set<std::string>& allowable_types)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    FREEMAPS_ASSERT (db->key_exists (key));

    std::ostringstream os;

    os << get_line_number_message (db, key) << '\n';
    os << "not supported type of \"" << key << "\" whose type is \"";
    os << Utilities::enum_to_string (db->get_key_type (key)) << "\"\n";
    os << "the allowable types is:\n ";
    os << Utilities::get_rearranged_set (allowable_types, true, 1);

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::disallow_mutually_exclusive(
    const InputDatabase* db,
    const std::string& key_1,
    const std::string& key_2)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    FREEMAPS_ASSERT (db->key_exists (key_1) && db->key_exists (key_2));
    std::ostringstream os;

    os << get_line_number_message (db) << '\n';
    os << "\"" << key_1 << "\" and \"" << key_2 << "\" can not set together";

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::use_improper_string_value(
    const InputDatabase* db,
    const std::string& key,
    const std::string& tip_info,
    const std::set<std::string>& allowable_values)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    db->check_requisite_key (key, DataType::STRING, false, true);

    const std::vector<std::string>& values = db->get_string_vector (key);
    for (std::size_t pos = 0; pos < values.size(); ++pos)
    {
        const std::string& value = values[pos];
        if (allowable_values.count (value) == 0)
        {
            use_improper_string_value (db, key, pos, tip_info, allowable_values);
        }
    }

    FREEMAPS_FIND_BUG();
}



void
LogMessage::use_improper_string_value(
    const InputDatabase* db,
    const std::string& key,
    const std::string& value,
    const std::string& error_message)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    db->check_optional_key (key, DataType::STRING, true, true);

    if (db->key_exists (key))
    {
        const std::vector<std::string>& values = db->get_string_vector (key);
        for (std::size_t pos = 0; pos < values.size(); ++pos)
        {
            if (value == values[pos])
            {
                use_improper_string_value (db, key, pos, error_message);
            }
        }

        FREEMAPS_ERROR ("error, not found key = " << key << ", value = " << value);
    }
    else
    {
        std::ostringstream oss;
        oss << "when using default parameter of " << key << " = \"" << value << "\"\n";
        oss << error_message;

        unknown_error (db, key, oss.str());
    }
}



void
LogMessage::use_improper_string_value(
    const InputDatabase* db,
    const std::string& key,
    const std::string& value,
    const std::string& tip_info,
    const std::set<std::string>& allowable_values)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    db->check_optional_key (key, DataType::STRING, true, true);

    if (db->key_exists (key))
    {
        const std::vector<std::string>& values = db->get_string_vector (key);
        for (std::size_t pos = 0; pos < values.size(); ++pos)
        {
            if (value == values[pos])
            {
                use_improper_string_value (db, key, pos, tip_info, allowable_values);
            }
        }

        FREEMAPS_FIND_BUG();
    }
    else
    {
        std::ostringstream oss;
        oss << "when using default parameter of " << key << " = \"" << value << "\"\n";
        oss << tip_info << std::endl;
        if (!allowable_values.empty())
        {
            oss << "the following values are acceptable:\n";

            oss << Utilities::get_rearranged_set (allowable_values, true, 1) << '\n';

            std::string gauss_value;
            bool has_tip = Utilities::get_similar_string(
                               value,
                               allowable_values,
                               gauss_value,
                               3);
            if (has_tip)
            {
                oss << "\ndo you mean \"" << gauss_value << "\" ?" << std::endl;
            }
        }

        unknown_error (db, key, oss.str());
    }
}



void
LogMessage::use_improper_string_value(
    const InputDatabase* db,
    const std::string& key,
    const int num,
    const std::string& tip_info,
    const std::set<std::string>& allowable_values)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    db->check_requisite_key (key, DataType::STRING, false, true);

    const std::vector<std::string> values = db->get_string_vector (key);
    FREEMAPS_ASSERT (num >= 0 && num < static_cast<int>(values.size()));

    std::ostringstream os;
    os << get_line_number_message (db, key) << '\n';
    os << "unrecognized " << key;
    if (values.size() > 1)
    {
        os << "[" << num << "]";
    }
    os << " = \"" << values[num] << "\"\n";
    os << tip_info << '\n';

    if (!allowable_values.empty())
    {
        os << "the following values are acceptable:\n";

        os << Utilities::get_rearranged_set (allowable_values, true, 1) << '\n';

        std::string gauss_value;
        bool has_tip = Utilities::get_similar_string(
                           values[num],
                           allowable_values,
                           gauss_value,
                           3);
        if (has_tip)
        {
            os << "\ndo you mean \"" << gauss_value << "\" ?" << std::endl;
        }
    }

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::use_improper_string_value(
    const InputDatabase* db,
    const std::string& key,
    const int num,
    const std::string& error_message)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    db->check_requisite_key (key, DataType::STRING, false, true);
    const std::vector<std::string> values = db->get_string_vector (key);
    FREEMAPS_ASSERT (num >= 0 && num < static_cast<int>(values.size()));
    std::ostringstream os;
    os << get_line_number_message (db, key) << '\n';
    os << "unrecognized " << key;
    if (values.size() > 1)
    {
        os << "[" << num << "]";
    }
    os << " = \"" << values[num] << "\"\n";
    os << error_message << std::endl;

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::use_improper_string_value_as_map_key(
    const InputDatabase* db,
    const std::string& key,
    const std::string& value,
    const std::string& tip_info,
    const std::set<std::string>& allowable_values)
{
    if (db->key_exists (key))
    {
        FREEMAPS_ASSERT (db->get_key_type (key) == DataType::STRING_STRING_MAP);
        std::ostringstream os;
        os << get_line_number_message (db, key) << '\n';
        os << get_log_info_from_map (key, db->get_string_string_map (key), 0, true, true) << '\n';
        os << "one of the map's key = \"" << value << "\" is not an acceptable value.\n";
        os << tip_info << '\n';

        if (!allowable_values.empty())
        {
            os << "the following values are acceptable:\n";

            os << Utilities::get_rearranged_set (allowable_values, true, 1) << '\n';

            std::string gauss_value;
            bool has_tip = Utilities::get_similar_string(
                               value,
                               allowable_values,
                               gauss_value,
                               3);
            if (has_tip)
            {
                os << "\ndo you mean \"" << gauss_value << "\" ?" << std::endl;
            }
        }

        FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
    }
    else
    {
        std::ostringstream os;

        os << "when use default value to set map of \"" << key << "\", one of it's key \"" << value << "\" is not acceptable.\n";
        os << tip_info << '\n';

        if (!allowable_values.empty())
        {
            os << "the following values are acceptable:\n";

            os << Utilities::get_rearranged_set (allowable_values, true, 1) << '\n';

            std::string gauss_value;
            bool has_tip = Utilities::get_similar_string(
                               value,
                               allowable_values,
                               gauss_value,
                               3);
            if (has_tip)
            {
                os << "\ndo you mean \"" << gauss_value << "\" ?" << std::endl;
            }
        }

        unknown_error (db, key, os.str());
    }
}



void
LogMessage::use_improper_string_value_as_map_value(
    const InputDatabase* db,
    const std::string& key,
    const std::string& value,
    const std::string& tip_info,
    const std::set<std::string>& allowable_values)
{
    if (db->key_exists (key))
    {
        FREEMAPS_ASSERT (db->get_key_type (key) == DataType::STRING_STRING_MAP);
        std::ostringstream os;
        os << get_line_number_message (db, key) << '\n';
        os << get_log_info_from_map (key, db->get_string_string_map (key), 0, true, true) << '\n';
        os << "one of the map's value = \"" << value << "\" is not an acceptable value.\n";
        os << tip_info << '\n';

        if (!allowable_values.empty())
        {
            os << "the following values are acceptable:\n";

            os << Utilities::get_rearranged_set (allowable_values, true, 1) << '\n';

            std::string gauss_value;
            bool has_tip = Utilities::get_similar_string(
                               value,
                               allowable_values,
                               gauss_value,
                               3);
            if (has_tip)
            {
                os << "\ndo you mean \"" << gauss_value << "\" ?" << std::endl;
            }
        }

        FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
    }
    else
    {
        std::ostringstream os;

        os << "when use default value to set map of \"" << key << "\", one of it's value \"" << value << "\" is not acceptable.\n";
        os << tip_info << '\n';

        if (!allowable_values.empty())
        {
            os << "the following values are acceptable:\n";

            os << Utilities::get_rearranged_set (allowable_values, true, 1) << '\n';

            std::string gauss_value;
            bool has_tip = Utilities::get_similar_string(
                               value,
                               allowable_values,
                               gauss_value,
                               3);
            if (has_tip)
            {
                os << "\ndo you mean \"" << gauss_value << "\" ?" << std::endl;
            }
        }

        unknown_error (db, key, os.str());
    }
}



void
LogMessage::use_improper_string_value_in_map(
    const InputDatabase* db,
    const std::string& key,
    const std::string& value,
    const std::string& tip_info,
    const std::set<std::string>& allowable_values)
{
    if (db->key_exists (key))
    {
        FREEMAPS_ASSERT (db->get_key_type (key) == DataType::STRING_STRING_MAP);
        std::ostringstream os;
        os << get_line_number_message (db, key) << '\n';
        os << get_log_info_from_map (key, db->get_string_string_map (key), 0, true, true) << '\n';
        os << "one of the map's key or value = \"" << value << "\" is not an acceptable value.\n";
        os << tip_info << '\n';

        if (!allowable_values.empty())
        {
            os << "the following values are acceptable:\n";

            os << Utilities::get_rearranged_set (allowable_values, true, 1) << '\n';

            std::string gauss_value;
            bool has_tip = Utilities::get_similar_string(
                               value,
                               allowable_values,
                               gauss_value,
                               3);
            if (has_tip)
            {
                os << "\ndo you mean \"" << gauss_value << "\" ?" << std::endl;
            }
        }

        FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
    }
    else
    {
        std::ostringstream os;

        os << "when use default value to set map of \"" << key << "\", one of it's key or value \"" << value << "\" is not acceptable.\n";
        os << tip_info << '\n';

        if (!allowable_values.empty())
        {
            os << "the following values are acceptable:\n";

            os << Utilities::get_rearranged_set (allowable_values, true, 1) << '\n';

            std::string gauss_value;
            bool has_tip = Utilities::get_similar_string(
                               value,
                               allowable_values,
                               gauss_value,
                               3);
            if (has_tip)
            {
                os << "\ndo you mean \"" << gauss_value << "\" ?" << std::endl;
            }
        }

        unknown_error (db, key, os.str());
    }
}



void
LogMessage::use_improper_integer_value(
    const InputDatabase* db,
    const std::string& key,
    const int value,
    const std::string& error_message)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    db->check_requisite_key (key, DataType::INTEGER, false, true);
    const std::vector<int>& values = db->get_integer_vector (key);
    for (std::size_t pos = 0; pos < values.size(); ++pos)
    {
        if (value == values[pos])
        {
            std::ostringstream os;
            os << get_line_number_message (db, key) << '\n';
            os << "error in:\n" << key;
            if (values.size() > 1)
            {
                os << "[" << pos << "]";
            }
            os << " = " << value << '\n';

            os << error_message;

            FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
        }
    }

    FREEMAPS_ERROR ("not found ?");
}



void
LogMessage::use_improper_integer_value(
    const InputDatabase* db,
    const std::string& key,
    const int num,
    const std::string& tip_info,
    const std::set<int>& allowable_values)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    db->check_requisite_key (key, DataType::INTEGER, false, true);

    const std::vector<int> values = db->get_integer_vector (key);
    FREEMAPS_ASSERT (num >= 0 && num < static_cast<int>(values.size()));

    std::ostringstream os;
    os << get_line_number_message (db, key) << '\n';
    os << "unrecognized " << key;
    if (values.size() > 1)
    {
        os << "[" << num << "]";
    }
    os << " = \"" << values[num] << "\"\n";
    os << tip_info << '\n';

    if (!allowable_values.empty())
    {
        os << "the following values are acceptable:\n";

        os << Utilities::get_rearranged_set (allowable_values, false, 1) << '\n';
    }

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::use_improper_double_value(
    const InputDatabase* db,
    const std::string& key,
    const double value,
    const std::string& error_message)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    db->check_requisite_key (key, DataType::DOUBLE, false, true);
    const std::vector<double>& values = db->get_double_vector (key);
    for (std::size_t pos = 0; pos < values.size(); ++pos)
    {
        if (MathUtilities<double>::equal_eps (value, values[pos]))
        {
            std::ostringstream os;
            os << get_line_number_message (db, key) << '\n';
            os << "error in:\n" << key;
            if (values.size() > 1)
            {
                os << "[" << pos << "]";
            }
            os << " = " << value << '\n';

            os << error_message;

            FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
        }
    }

    FREEMAPS_FIND_BUG();
}



void
LogMessage::disallow_different_size (
    const InputDatabase* db,
    const std::string& key_1,
    const std::string& key_2)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    FREEMAPS_ASSERT (db->key_exists (key_1));
    FREEMAPS_ASSERT (db->key_exists (key_2));

    std::ostringstream os;

    os << get_line_number_message (db) << '\n';
    os << "error in\n";
    os << "size of \"" << key_1 << "\" is " << db->get_array_size (key_1) << '\n';
    os << "size of \"" << key_2 << "\" is " << db->get_array_size (key_2) << '\n';
    os << "this is disallowable, they should have same size";

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::disallow_array_size(
    const InputDatabase* db,
    const std::string& key,
    const int allowable_size,
    const std::string& error_message)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    std::ostringstream os;

    FREEMAPS_ASSERT (db->key_exists (key));
    os << get_line_number_message (db, key) << '\n';
    os << "\"" << key << "\" have size of " << db->get_array_size (key) << " is not allowable" << '\n';
    os << "it should have a size of " << allowable_size << '\n';
    os << error_message;

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::disallow_non_dim_size(
    const InputDatabase* db,
    const std::string& key)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    FREEMAPS_ASSERT (db->key_exists (key));
    std::ostringstream os;

    const int dim = InfoManager::get_instance()->get_common_info()->get_dim();
    os << get_line_number_message (db, key) << '\n';
    os << "\"" << key << "\" as an array has size of " << db->get_array_size (key) << ",\n";
    os << "it should have a size equal to Dimension = " << dim << '\n';

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::unrecognized_key(
    const InputDatabase* db,
    const std::string& unrecognized_key,
    const std::set<std::string>& allowable_keys)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    FREEMAPS_ASSERT (db->key_exists (unrecognized_key));

    std::ostringstream os;

    os << get_line_number_message (db, unrecognized_key) << '\n';
    os << "unrecognized key of \"" << unrecognized_key << "\"\n";
    os << "in the database, the following keys are supported:\n";
    os << Utilities::get_rearranged_set (allowable_keys, true, 1);

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::unrecognized_key(
    const InputDatabase* db,
    const std::string& unrecognized_key,
    const std::string& suggested_key,
    const std::set<std::string>& allowable_keys)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    FREEMAPS_ASSERT (db->key_exists (unrecognized_key));

    std::ostringstream os;

    os << get_line_number_message (db, unrecognized_key) << '\n';
    os << "unrecognized key of \"" << unrecognized_key << "\"\n";
    os << "in the database, the following keys are supported:\n";
    os << Utilities::get_rearranged_set (allowable_keys, true, 1) << "\n\n";
    os << "do you mean \"" << suggested_key << "\" ?";

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::unknown_error(
    const std::string& error_message)
{
    std::ostringstream os;
    os << error_message;

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::unknown_error(
    const InputDatabase* db,
    const std::string& error_message)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    std::ostringstream os;
    os << get_line_number_message (db) << '\n';
    os << error_message;

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::unknown_error(
    const InputDatabase* db,
    const std::string& key,
    const std::string& error_message)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    std::ostringstream os;
    os << get_line_number_message (db, key) << '\n';
    os << "error of key = \"" << key << "\"\n";
    os << error_message;

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::unfound_file(
    const InputDatabase* db,
    const std::string& key,
    const std::string& file_name)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    db->check_optional_key (key, DataType::STRING, false, false);

    std::ostringstream os;

    if (db->key_exists (key))
    {
        os << get_line_number_message (db, key) << '\n';
        os << "error in:\n" << key << " = " << "\"" << db->get_string (key) << "\"\n";
        os << "can not find the file of \"" << file_name << "\"";
    }
    else
    {
        os << get_line_number_message (db) << '\n';
        os << "error in set key of \"" << key << "\" use default value.\n\n";
        os << "can not find the file of \"" << file_name << "\"";
    }

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::unfound_directory(
    const InputDatabase* db,
    const std::string& key,
    const std::string& dir_name)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    db->check_optional_key (key, DataType::STRING, false, false);

    std::ostringstream os;

    if (db->key_exists (key))
    {
        os << get_line_number_message (db, key) << '\n';
        os << "error in:\n" << key << " = " << "\"" << db->get_string (key) << "\"";
        os << "can not find the directory of \"" << dir_name << "\"";
    }
    else
    {
        os << get_line_number_message (db) << '\n';
        os << "error in set key of \"" << key << "\" use default value.\n";
        os << "can not find the directory of \"" << dir_name << "\"";
    }

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}



void
LogMessage::unsupported_library(
    const InputDatabase* db,
    const std::string& key,
    const std::string& value,
    const std::string& required_library)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    use_improper_string_value (
        db,
        key,
        value,
        "The current version has not built with supports of library \"" + required_library + "\"");
}



void
LogMessage::unsupported_library(
    const InputDatabase* db,
    const std::string& key,
    const std::string& required_library)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    unknown_error(
        db,
        key,
        "The current version has not built with supports of library \"" + required_library + "\"");
}



void
LogMessage::write_log_info_to_file()
{
#if 0
        PLOG << *(InfoManager::get_instance()) << std::endl;
        const MeshInfo* mesh_info = InfoManager::get_instance()->get_mesh_info();

        if (mesh_info->use_structured_mesh())
        {
#ifdef FREEMAPS_HAVE_SAMRAI
            PLOG << '\n' << *(BaseEnsemble::get_instance()->get_structured_mesh()) << '\n';
#else
            FREEMAPS_FIND_BUG();
#endif
        }

        if (mesh_info->use_unstructured_mesh())
        {
            if (BaseEnsemble::get_instance()->get_unstructured_mesh() != NULL)
            {
                //FREEMAPS_ERROR ("not finished");
                //PLOG << '\n'<< *(base_ensemble->get_unstructured_mesh()) << std::endl;
                /*
                 * now nothing to do
                 */
            }
        }

#ifdef FREEMAPS_HAVE_SAMRAI
        if (MonteCarloEnsemble::get_instance()->is_used())
        {
            PLOG << '\n' << *(MonteCarloEnsemble::get_instance()) << std::endl;
        }
#endif

        PLOG << '\n' << *(SimulationEnsemble::get_instance()) << std::endl;

        PLOG << '\n' << *(SolveController::get_instance()) << '\n' << std::endl;
#endif
}



void
LogMessage::write_conf_info_to_file(const std::string& conf_file_name)
{
    //std::cout<<__FILE__<<__LINE__<< " ----write_conf_info_to_file-----" << std::endl;

    std::filebuf fb;
    fb.open(conf_file_name, std::ios::out);
    std::ostream setup_writer(&fb);

    setup_writer << *(InfoManager::get_instance()) << std::endl;

    setup_writer << "\n" << *(SimulationEnsemble::get_instance()) << std::endl;

    fb.close();
}



std::string
LogMessage::get_log_info (
    const std::ostringstream& info,
    const int num_prefix,
    const bool leave_first_line_unchanged,
    const std::string& prefix)
{
    return get_log_info (info.str(), num_prefix, leave_first_line_unchanged, prefix);
}



std::string
LogMessage::get_log_info (
    const std::string& info,
    const int num_prefix,
    const bool leave_first_line_unchanged,
    const std::string& prefix)
{
    std::string result (info);
    std::string total_prefix = get_prefix(num_prefix, prefix);
    if (!leave_first_line_unchanged)
    {
        result.insert (0, total_prefix);
    }

    std::string::size_type length = num_prefix * prefix.size();

    std::string::size_type pos = result.find ("\n");
    while (pos != std::string::npos)
    {
        result.insert (pos + 1, total_prefix);
        pos = result.find ("\n", pos + 1 + length);
    }

    return result;
}



std::string
LogMessage::get_prefix(
    const int num_prefix,
    const std::string& prefix)
{
    std::string total_prefix("");
    for (int i = 0; i < num_prefix; ++i)
    {
        total_prefix += prefix;
    }

    return total_prefix;
}



std::string
LogMessage::get_bool_string (
    const bool bool_val)
{
    return (bool_val ? "TRUE" : "FALSE");
}



std::string
LogMessage::get_equal_width_string (
    const std::string& str,
    const int width)
{
    std::string result (str);
    const int num_postfix = width - str.size();
    if (num_postfix > 0)
    {
        for (int i = 0; i < num_postfix; ++i)
        {
            result += " ";
        }
    }

    return result;
}



std::string
LogMessage::get_equal_width_string (
    const std::string& str,
    const int num_prefix,
    const int width)
{
    return get_equal_width_string (get_prefix (num_prefix) + str, width + num_prefix);
}



void
LogMessage::show_verbose_info(
    const std::string& verbose_info)
{
    std::cout << verbose_info << std::endl;
}



void
LogMessage::show_function_info(
    const std::string& object_name,
    const std::string& function_name)
{
    if (InfoManager::get_instance()->get_common_info()->get_verbose_level() >= 100)
    {
        std::cout << "Now run function \"" << function_name << "\" in object \"" << object_name << "\"" << std::endl;
    }
}

}
